package interpreter;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import heap.Heap;
import heap.Types;

public class AssignmentInst implements Instruction {
	
	private String lVal;
	private String rVal;

	public AssignmentInst(String lVal, String rVal) {
		super();
		this.lVal = lVal;
		this.rVal = rVal;
	}

	@Override
	public void execute() {
		
		Heap heap = Heap.getInstance();
		String leftVarName;
		
		//najpierw RVALUE:
		RValue rValue = parseRValue(rVal);	
		
		if (lVal.contains(".")){
			
			String[] splitted = lVal.split("\\.");
			
			leftVarName = splitted[0];
			
			if (heap.typeOf(leftVarName).equals(Types.T)) {

				int leftVarPosition = heap.getPosition(leftVarName);

				for (int i = 1; i < splitted.length - 1; i++) {
					String part = splitted[i];
					if (part.equals("f1")) {
						leftVarPosition = heap.getF1Position(leftVarPosition);
					} else if (part.equals("f2")) {
						leftVarPosition = heap.getF2Position(leftVarPosition);
					} else {
						
					}
				}				
				
				String lastPart = splitted[splitted.length - 1];

				if (lastPart.equals("f1")) {
					// przepisanie referencji do nowego obiektu w polu f1
					heap.setF1Position(leftVarPosition, rValue.getPosition());
				} else if (lastPart.equals("f2")) {
					// przepisanie referencji do nowego obiektu w polu f2
					heap.setF2Position(leftVarPosition, rValue.getPosition());
				} else if (lastPart.equals("data")) {
					// przypisnie wartosci do pola data w objecie typu T
					heap.setData(leftVarPosition, rValue.getValue());					
				} else {
					// wyjatek - nie ma takiego pola
				}
			}else{
				//wyjatek - typ S nie posiada pol
			}
			
			
			
		}else{			
			leftVarName = lVal;
			Types type = heap.typeOf(leftVarName);

			if (type.equals(Types.S)) {
				if (rValue.getStringConstant() == null)
					heap.redefine(leftVarName, rValue.getPosition());
				else 
					heap.defineS(leftVarName, rValue.getStringConstant());
			} else if (type.equals(Types.T)) {
				heap.redefine(leftVarName, rValue.getPosition());
			} else {
				// wyjatek NULL
			}
			
		}		
	}
	
	
	
	private RValue parseRValue(String lvalue){
		
		Heap heap = Heap.getInstance();
		String rightVarName;
		
		int value = 0;
		int position = 0;
		String stringConstant = null;
		
		
		if (rVal.contains(".")){
			
			String[] splittedRValue = rVal.split("\\.");
			
			rightVarName = splittedRValue[0];
			
			if (heap.typeOf(rightVarName).equals(Types.T)) {

				int rightVarPosition = heap.getPosition(rightVarName);

				for (int i = 1; i < splittedRValue.length - 1; i++) {
					String part = splittedRValue[i];
					if (part.equals("f1")) {
						rightVarPosition = heap.getF1Position(rightVarPosition);
					} else if (part.equals("f2")) {
						rightVarPosition = heap.getF2Position(rightVarPosition);
					} else {
						// wyjatek - nie ma innego pola w typie T
					}
				}
		
				String lastPart = splittedRValue[splittedRValue.length - 1];

				if (lastPart.equals("f1")) {
					position = heap.getF1Position(rightVarPosition);
					
				} else if (lastPart.equals("f2")) {
					position = heap.getF2Position(rightVarPosition);
				}
				if (lastPart.equals("data")) {
					value = heap.getData(rightVarPosition);
					
				} else {
					// wyjatek - nie ma innego pola
				}
			}else{
				//wyjatek - typ S nie posiada pol
			}				
			
		}else{		
			
			Pattern pattern = Pattern.compile("^\"(.+)\"$");
			Matcher matcher = pattern.matcher(rVal);
			
			if (matcher.matches()){
				//string constant			
				stringConstant = matcher.group(1);
			}else if(!rVal.equals("NULL")){
				Pattern numberPattern = Pattern.compile("[0-9]*");
				Matcher numberMatcher = numberPattern.matcher(rVal);
				
				if (numberMatcher.matches()){
					value = Integer.parseInt(rVal);
				}else{
					position = heap.getPosition(rVal);
				}
				
			}else{
				position = 0;
			}
		}
		
		return new RValue(value, position, stringConstant);
		
	}
		
	private class RValue {
		private int value;
		private int position;
		private String stringConstant;
		
		public RValue(int value, int position, String stringConstant) {
			super();
			this.value = value;
			this.position = position;
			this.stringConstant = stringConstant;
		}
        	
		public int getValue() {
			return value;
		}
		
		public int getPosition() {
			return position;
		}
		
		public String getStringConstant() {
			return stringConstant;
		}
		
	}

}

